package net.minecraft.src;

import java.util.*;
public class BlockSequencer extends  BlockContainer
{
	private Random random;
	public class ScheduleData
	{
		boolean[]  sequence;
		long  time;
	};
	public boolean  powerState = false;

	Map< Object,int []  > sides = new HashMap< Object,int [] >();
	Map< Object,int []  > shifts = new HashMap< Object,int [] >();

	private static  ArrayList<Coords> switched= new ArrayList<Coords>();
	private static  Map<Coords,ScheduleData> sequences= new HashMap<Coords,ScheduleData >();  

	static final int basePeriod  = 80;

	public int getRenderBlockPass()
	{
		return 0;
	}
	protected BlockSequencer(int i, int j,boolean power)
	{
		super(i, j,Material.circuits);
		random = new Random();
		powerState = power;

		//private  int [] sides = {5,2,4,3};

		sides.put( new Integer(5), new int[] {2,4,3} );
		sides.put( new Integer(2), new int[] {4,3,5} );
		sides.put( new Integer(4), new int[] {3,5,2} );
		sides.put( new Integer(3), new int[] {5,2,4} );


		shifts.put( new Integer(5), new int[] {1,0,0} );
		shifts.put( new Integer(4), new int[] {-1,0,0} );
		shifts.put( new Integer(2), new int[] {0,0,-1} );
		shifts.put( new Integer(3), new int[] {0,0,1} );

	}    
	// 
	public int getBlockTextureFromSideAndMetadata(int i, int j)
	{

		if( i ==  j ) 
		{
			return mod_AsPj.sequencerBack;
		}
		else if( i ==  0 )
		{
			return mod_AsPj.sequencerUp;
		}
		else if( i ==  1 )
		{
			return mod_AsPj.sequencerDown;
		}
		else
		{
			return blockIndexInTexture;
		}
	}
	public void onBlockPlacedBy(World world, int i, int j, int k, EntityLiving entityliving)
	{
		int l = MathHelper.floor_double((double)((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3;
		if (l == 0)
		{
			world.setBlockMetadataWithNotify(i, j, k, 2);
		}
		if (l == 1)
		{
			world.setBlockMetadataWithNotify(i, j, k, 5);
		}
		if (l == 2)
		{
			world.setBlockMetadataWithNotify(i, j, k, 3);
		}
		if (l == 3)
		{
			world.setBlockMetadataWithNotify(i, j, k, 4);
		}
	}

	public boolean blockActivated(World world, int i, int j, int k, EntityPlayer entityplayer)
	{
		if (world.isRemote)
		{
			return true;
		}


		ModLoader.openGUI(entityplayer, new GuiSequenzer(entityplayer.inventory, getTile(world, i, j, k))); 

		return true;
	}
	public void onBlockAdded(World world, int i, int j, int k)
	{

		Coords coords = new Coords(i,j,k);
		if(!switched.contains(coords) )
		{
			super.onBlockAdded(world, i, j, k);

		}
		else
			switched.remove(coords);

		if(sequences.containsKey(coords))
			sequences.remove(coords);

		if(!powerState)
		{
			getTile(world, i, j, k).resetCounter();
		}
		world.scheduleBlockUpdate(i, j, k, blockID, 1);

	}

	public void onBlockRemoval(World world,  int par2, int par3, int par4)
	{

		Coords coords = new Coords( par2, par3, par4);
		if(!switched.contains(coords) )
		{


			TileSequenzer tileSequencer = getTile( world,par2, par3, par4);
			if (tileSequencer != null)
			{
				/* need corections */
					for (int i = 0; i < tileSequencer.getSizeInventory(); i++)
					{
						ItemStack itemstack = tileSequencer.getStackInSlotOnClosing(i);

						if (itemstack != null)
		                {
		                    float f = random.nextFloat() * 0.8F + 0.1F;
		                    float f1 = random.nextFloat() * 0.8F + 0.1F;
		                    float f2 = random.nextFloat() * 0.8F + 0.1F;

		                    while (itemstack.stackSize > 0)
		                    {
		                        int j = random.nextInt(21) + 10;

		                        if (j > itemstack.stackSize)
		                        {
		                            j = itemstack.stackSize;
		                        }

		                        itemstack.stackSize -= j;
		                        EntityItem entityitem = new EntityItem(world, (float)par2 + f, (float)par3 + f1, (float)par4 + f2, new ItemStack(itemstack.itemID, j, itemstack.getItemDamage()));

		                        if (itemstack.hasTagCompound())
		                        {
		                            entityitem.item.setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
		                        }

		                        float f3 = 0.05F;
		                        entityitem.motionX = (float)random.nextGaussian() * f3;
		                        entityitem.motionY = (float)random.nextGaussian() * f3 + 0.2F;
		                        entityitem.motionZ = (float)random.nextGaussian() * f3;
		                        world.spawnEntityInWorld(entityitem);
		                    }
		                }
				}
			}
			super.onBlockRemoval(world, par2, par3, par4);
		}
	

	}
	public void updateTick(World world, int i, int j, int k, Random random)
	{   

		boolean flag = func_30002_h(world, i, j, k);
		if(powerState == false)
			getTile(world, i, j, k).resetCounter();

		if (powerState != flag)
		{
			switched.add(new Coords(i,j,k));
			int newBlockId =
				this.blockID == mod_AsPj.blockSequencerIdle.blockID ? mod_AsPj.blockSequencerActive.blockID : mod_AsPj.blockSequencerIdle.blockID;
			world.setBlockAndMetadataWithNotify(i, j, k, newBlockId , world.getBlockMetadata(i, j, k)); 



		}
		if(powerState == true)
		{

			/* Fix  this */
			creteScheduleUnit(world, i, j, k);
		}
	}
	private void  creteScheduleUnit(World world, int i, int j, int k)
	{
		ScheduleData scheduleData = new ScheduleData();

		Coords  temp=new Coords(i, j, k);

		long arriveTime = world.getWorldTime();
		long scheduleTime = 0;
		if(sequences.containsKey(temp))
		{
			scheduleTime =  Math.abs( sequences.get(temp).time - arriveTime )%  basePeriod;

			sequences.remove(temp);
		}
		scheduleTime += tickRate( world,  i,  j, k);
		arriveTime += scheduleTime;
		assert(arriveTime > 0);
		assert(scheduleTime > 0);
		scheduleData.sequence = getTile(world, i, j, k).getNextSequence();
		if( scheduleData.sequence != null )
		{
			scheduleData.time = arriveTime;
			sequences.put(temp, scheduleData);
			world.scheduleBlockUpdate(i, j, k, blockID, (int)scheduleTime);  
		}
		else
		{
			//sequences.put(temp, null);    
		}       
		world.notifyBlockChange(i, j, k, mod_AsPj.blockSequencerActive.blockID);        
	}

	public boolean isPoweringTo(IBlockAccess iblockaccess, int i, int j, int k, int l)
	{

		if(!powerState)
			return false;
		ScheduleData  secheduleData = sequences.get(new Coords(i,j,k));

		if( secheduleData == null )
			return  false;
		boolean [] currentSequence= secheduleData.sequence;

		if(currentSequence == null)
			return  false;
		int meta =iblockaccess.getBlockMetadata(i, j, k);
		
		if( !sides.containsKey( meta ) )
			return false;
		
		meta = sides.get(meta)[1];
		if(l == sides.get(meta)[0])
			return currentSequence[2];
		else if(l == sides.get(meta)[1])
			return currentSequence[1];
		else if(l == sides.get(meta)[2])         
			return currentSequence[0];

		return  false;

	}


	private boolean func_30002_h(World world, int i, int j, int k)
	{

		int  meta = world.getBlockMetadata(i, j, k);

		if( !shifts.containsKey( meta ) )
			return false;
		
		return world.isBlockIndirectlyProvidingPowerTo(
			i + shifts.get(meta)[0]
		, j + shifts.get(meta)[1]
		, k + shifts.get(meta)[2]
		, meta);

	}


	public int tickRate(World world, int i, int j, int k)
	{

		int  tickRate = basePeriod  /( 1 + getTile(world, i, j, k).getTime());

		return  tickRate;

	}


	public boolean renderAsNormalBlock()
	{
		return false;
	}

	public void onNeighborBlockChange(World world, int i, int j, int k, int l)
	{
		boolean flag = func_30002_h(world, i, j, k);

		if (powerState != flag)
		{
			world.scheduleBlockUpdate(i, j, k, blockID, 1);
		}


	}

	private TileSequenzer getTile(World world, int i, int j, int k)
	{
		return (TileSequenzer)world.getBlockTileEntity(i, j, k);

	}

    public int idDropped(int i, Random random, int j)
    {
        return mod_AsPj.blockSequencerIdle.blockID;
    }
	public TileEntity getBlockEntity()
	{
		return new TileSequenzer();

	}

}
